//
//  HCObjCDefines.h
//  HCToolBox
//
//  Created by Hotacool on 2019/3/19.
//

#ifndef HCObjCDefines_h
#define HCObjCDefines_h

/** 非空判断  */
#define hcObjectIsNull(_object) (_object == nil \
|| [_object isKindOfClass:[NSNull class]])

/** 非空判断  */
#define hcObjectIsEmpty(_object) (_object == nil \
|| [_object isKindOfClass:[NSNull class]] \
|| ([_object respondsToSelector:@selector(length)] && [(NSData *)_object length] == 0) \
|| ([_object respondsToSelector:@selector(count)] && [(NSArray *)_object count] == 0))

/** __weak  */
#ifndef weakIt
#if __has_feature(objc_arc)

#define weakIt( x ) \
_Pragma("clang diagnostic push") \
_Pragma(ClangWarningConcat("-Wshadow")) \
autoreleasepool{} __weak __typeof__(x) __weak_##x##__ = x; \
_Pragma("clang diagnostic pop")
#else

#define weakIt( x ) \
_Pragma("clang diagnostic push") \
_Pragma(ClangWarningConcat("-Wshadow")) \
autoreleasepool{} __block __typeof__(x) __block_##x##__ = x; \
_Pragma("clang diagnostic pop")

#endif
#endif
/** __strong  */
#ifndef strongIt
#if __has_feature(objc_arc)

#define strongIt( x ) \
_Pragma("clang diagnostic push") \
_Pragma(ClangWarningConcat("-Wshadow")) \
try{} @finally{} __typeof__(x) x = __weak_##x##__; \
_Pragma("clang diagnostic pop")

#else

#define strongIt( x ) \
_Pragma("clang diagnostic push") \
_Pragma(ClangWarningConcat("-Wshadow")) \
try{} @finally{} __typeof__(x) x = __block_##x##__; \
_Pragma("clang diagnostic pop")

#endif
#endif

#pragma mark - Meta Marcos
#define _HCSynthesizeId(_getterName, _setterName, _policy) \
_Pragma("clang diagnostic push") _Pragma(ClangWarningConcat("-Wmismatched-parameter-types")) _Pragma(ClangWarningConcat("-Wmismatched-return-types"))\
static char kAssociatedObjectKey_##_getterName;\
- (void)_setterName:(id)_getterName {\
objc_setAssociatedObject(self, &kAssociatedObjectKey_##_getterName, _getterName, OBJC_ASSOCIATION_##_policy##_NONATOMIC);\
}\
\
- (id)_getterName {\
return objc_getAssociatedObject(self, &kAssociatedObjectKey_##_getterName);\
}\
_Pragma("clang diagnostic pop")

#define _HCSynthesizeNonObject(_getterName, _setterName, _type, valueInitializer, valueGetter) \
_Pragma("clang diagnostic push") _Pragma(ClangWarningConcat("-Wmismatched-parameter-types")) _Pragma(ClangWarningConcat("-Wmismatched-return-types"))\
static char kAssociatedObjectKey_##_getterName;\
- (void)_setterName:(_type)_getterName {\
objc_setAssociatedObject(self, &kAssociatedObjectKey_##_getterName, [NSNumber valueInitializer:_getterName], OBJC_ASSOCIATION_RETAIN_NONATOMIC);\
}\
\
- (_type)_getterName {\
return [((NSNumber *)objc_getAssociatedObject(self, &kAssociatedObjectKey_##_getterName)) valueGetter];\
}\
_Pragma("clang diagnostic pop")


#pragma mark - Objcet macro
/// @property(nonatomic, strong) id xxx
#define hcSynthesizeIdStrongProperty(_getterName, _setterName) _HCSynthesizeId(_getterName, _setterName, RETAIN)

/// @property(nonatomic, weak) id xxx
#define hcSynthesizeIdWeakProperty(_getterName, _setterName) _HCSynthesizeWeakId(_getterName, _setterName)

/// @property(nonatomic, copy) id xxx
#define hcSynthesizeIdCopyProperty(_getterName, _setterName) _HCSynthesizeId(_getterName, _setterName, COPY)

#pragma mark - NSObjcet macro
#define hcSwizzleInstanceMethods(_class, _originSEL, _newSEL)\
[NSObject swizzleMethodsFrom:_class selector:_originSEL to:_class newSelector:_newSEL];

#define dynamicProperty(CLASS, PROPERTY) \
dynamic PROPERTY; \
\
__attribute__((constructor)) \
static void hctb_ ## CLASS ## _ ## PROPERTY ## _dynamic (void) { \
Class cls = objc_getClass(# CLASS); \
NSCAssert([NSObject addDynamicProperty:# PROPERTY toClass:cls], @"@dynamiciProperty does not support weak properties (%@.%s)", # CLASS, # PROPERTY); \
\
}
#endif /* HCObjCDefines_h */
